package com.snail.service.impl;

import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradeQueryRequest;
import com.alipay.api.request.AlipayTradeWapPayRequest;
import com.alipay.api.response.AlipayTradeQueryResponse;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.snail.config.AlipayConfig;
import com.snail.eunms.OrderType;
import com.snail.exception.BusinessException;
import com.snail.exception.ErrorCode;
import com.snail.mapper.BizOrderMapper;
import com.snail.mapper.BizPaymentRecordMapper;
import com.snail.mapper.SysTeamSubscriptionMapper;
import com.snail.mapper.SysTeamUserMapper;
import com.snail.model.dto.PayRecordDto;
import com.snail.model.dto.PayStatusDto;
import com.snail.model.dto.QRCodeDto;
import com.snail.model.pojo.BizOrder;
import com.snail.model.pojo.BizPaymentRecord;
import com.snail.model.pojo.SysTeamSubscription;
import com.snail.model.pojo.SysTeamUser;
import com.snail.model.vo.BizOrderVo;
import com.snail.response.BaseResponse;
import com.snail.response.ResultUtils;
import com.snail.service.BizOrderService;
import com.snail.utils.QRCodeUtil;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author Monica
 * @description 针对表【biz_order(订单表)】的数据库操作Service实现
 * @createDate 2025-07-23 14:30:24
 */
@Service
@Slf4j
public class BizOrderServiceImpl extends ServiceImpl<BizOrderMapper, BizOrder> implements BizOrderService {
    @Autowired
    private BizOrderMapper bizOrderMapper;
    @Autowired
    private BizPaymentRecordMapper bizPaymentRecordMapper;
    @Value("${alipay.qrcodeUrl}")
    private String qrcodeUrl;
    @Autowired
    private AlipayConfig alipayConfig;
    @Autowired
    @Lazy
    private BizOrderService currentProxy;
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired
    private SysTeamSubscriptionMapper sysTeamSubscriptionMapper;

    @Autowired
    private SysTeamUserMapper sysTeamUserMapper;

    @Transactional
    @Override
    public BaseResponse<QRCodeDto> createOrder(BizOrderVo bizOrderVo) {
        // TODO 需要考虑是否唯一
        QRCodeDto qrCodeDto = new QRCodeDto();
        // 幂等性：不管多少次操作，他们的结果都一样,不能多次创建订单
        LambdaQueryWrapper<BizOrder> orderQueryWrapper = new LambdaQueryWrapper<>();
        orderQueryWrapper.eq(BizOrder::getUserId, bizOrderVo.getUserId());
        orderQueryWrapper.eq(BizOrder::getOrderType, bizOrderVo.getOrderType());
        orderQueryWrapper.eq(BizOrder::getTeamId, bizOrderVo.getTeamId());
        orderQueryWrapper.eq(BizOrder::getGoodsIds, bizOrderVo.getGoodsIds());
        BizOrder oldOrder = bizOrderMapper.selectOne(orderQueryWrapper);
        if (oldOrder == null) {
            // 生成订单记录
            BizOrder bizOrder = saveOrder(bizOrderVo);
            // 生成支付记录
            BizPaymentRecord payRecord = createPayRecord(bizOrder);

            // 创建二维码
            qrCodeDto = createQRCode(Integer.parseInt(bizOrder.getId().toString()));
        } else {
            // 订单已存在，直接返回二维码
            qrCodeDto = createQRCode(Integer.parseInt(oldOrder.getId().toString()));
        }
        return ResultUtils.success(qrCodeDto);
    }

    private BizPaymentRecord createPayRecord(BizOrder bizOrder) {
        if (bizOrder == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "订单不存在");
        }
        // 生成支付记录
        BizPaymentRecord payRecord = new BizPaymentRecord();
        String payNo = IdUtil.getSnowflake(1, 1).nextIdStr();
        payRecord.setPayNo(payNo);
        payRecord.setOrderId(bizOrder.getId());
        payRecord.setAmount(bizOrder.getAmount());
        payRecord.setStatus(0);
        int flag = bizPaymentRecordMapper.insert(payRecord);
        if (flag <= 0) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "支付记录创建失败");
        }
        return payRecord;
    }

    private BizOrder saveOrder(BizOrderVo bizOrderVo) {
        // 生成订单编号,雪花算法
        String orderNo = IdUtil.getSnowflake(1, 1).nextIdStr();
        BizOrder bizOrder = new BizOrder();
        BeanUtils.copyProperties(bizOrderVo, bizOrder);
        bizOrder.setOrderNo(orderNo);
        bizOrder.setStatus(0);
        bizOrder.setAmount(bizOrderVo.getAmount());
        int flag = bizOrderMapper.insert(bizOrder);
        if (flag <= 0) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "订单创建失败");
        }
        return bizOrder;
    }

    @Override
    public QRCodeDto createQRCode(Integer id) {
        BizOrder bizOrder = bizOrderMapper.selectById(id);
        if (bizOrder == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "订单不存在");
        }
        LambdaQueryWrapper<BizPaymentRecord> paymentRecordQueryWrapper = new LambdaQueryWrapper<>();
        paymentRecordQueryWrapper.eq(BizPaymentRecord::getOrderId, id);
        BizPaymentRecord payRecord = bizPaymentRecordMapper.selectOne(paymentRecordQueryWrapper);
        if (payRecord == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "支付记录不存在");
        }
        String url = String.format(qrcodeUrl, payRecord.getPayNo());
        String qrcode;
        try {
            qrcode = new QRCodeUtil().createQRCode(url, 200, 200);

        } catch (IOException e) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "二维码创建失败");
        }
        QRCodeDto qrCodeDto = new QRCodeDto();
        qrCodeDto.setQrCode(qrcode);
        return qrCodeDto;
    }

    @Override
    @Transactional
    public void requestPay(String payNo, Integer paymentMethod, HttpServletResponse httpResponse) throws IOException {

        BizPaymentRecord payRecord = getPayRecord(payNo);
        if (payRecord == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "订单不存在");
        }
        Integer status = payRecord.getStatus();
        if (status != 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "订单已支付,请勿重新支付");
        }
        BizOrder bizOrder = bizOrderMapper.selectById(payRecord.getOrderId());

        LambdaQueryWrapper<BizPaymentRecord> paymentRecordQueryWrapper = new LambdaQueryWrapper<>();
        paymentRecordQueryWrapper.eq(BizPaymentRecord::getPayNo, payNo);
        BizPaymentRecord bizPaymentRecord = bizPaymentRecordMapper.selectOne(paymentRecordQueryWrapper);
        bizPaymentRecord.setPaymentMethod(paymentMethod);
        bizPaymentRecord.setStatus(status);
        // 商品类型
        String nameByCode = OrderType.getNameByCode(bizOrder.getOrderType());

        AlipayClient alipayClient = new DefaultAlipayClient(alipayConfig.getUrl(), alipayConfig.getAppId(), alipayConfig.getRsaPrivateKey(), alipayConfig.getFormat(), alipayConfig.getCharset(), alipayConfig.getAlipayPublicKey(), alipayConfig.getSignType());
        // 创建支付宝sdk客户端对象
        AlipayTradeWapPayRequest alipayRequest = new AlipayTradeWapPayRequest();
        //填充业务参数
        alipayRequest.setBizContent("{" + "    \"out_trade_no\":\"" + payRecord.getPayNo() + "\"," + "    \"total_amount\":\"" + payRecord.getAmount() + "\"," + "    \"subject\":\"" + nameByCode + "\"," + "    \"product_code\":\"QUICK_WAP_WAY\"" + "  }");
        //调用SDK生成表单
        String form = null;
        try {
            form = alipayClient.pageExecute(alipayRequest).getBody();
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        httpResponse.setContentType("text/html;charset=" + alipayConfig.getCharset());
        //直接将完整的表单html输出到页面
        if (form != null) {
            httpResponse.getWriter().write(form);
        }
        httpResponse.getWriter().flush();
        httpResponse.getWriter().close();
    }

    @Override
    public BaseResponse<PayRecordDto> queryPayResult(String payNo) {
        // 判断支付记录是否存在
        BizPaymentRecord payRecord = getPayRecord(payNo);
        if (payRecord == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "订单不存在,请重新生成二维码");
        }
        Integer status = payRecord.getStatus();
        // 支付成功直接返回
        if (status != 0) {
            PayRecordDto payRecordDto = new PayRecordDto();
            BeanUtils.copyProperties(payRecord, payRecordDto);
            return ResultUtils.success(payRecordDto);
        }
        //从支付宝查询支付结果
        PayStatusDto payStatusDto = queryPayResultFromAlipay(payNo);
        //保存支付结果
        currentProxy.saveAliPayStatus(payStatusDto);
        //重新查询支付记录
        payRecord = getPayRecord(payNo);
        PayRecordDto payRecordDto = new PayRecordDto();
        BeanUtils.copyProperties(payRecord, payRecordDto);
        return ResultUtils.success(payRecordDto);
    }


    @Override
    @Transactional
    public void saveAliPayStatus(PayStatusDto payStatusDto) {
        //支付流水号
        String payNo = payStatusDto.getOutTradeNo();
        BizPaymentRecord payRecord = getPayRecord(payNo);
        if (payRecord == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "订单不存在,请重新生成二维码");
        }
        // 支付结果
        String tradeStatus = payStatusDto.getTradeStatus();
        if ("TRADE_SUCCESS".equals(tradeStatus)) {
            // 应支付金额
            BigDecimal amount = payRecord.getAmount();
            // 实际支付金额
            BigDecimal totalAmount = new BigDecimal(payStatusDto.getTotalAmount());
            // 校验金额是否一致
            if (amount.compareTo(totalAmount) != 0) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "校验支付结果失败");
            }
            // 更新支付状态
            payRecord.setStatus(1);
            // 支付宝交易号
            payRecord.setTradeNo(payStatusDto.getTradeNo());
            payRecord.setPaymentTime(LocalDateTime.now());

            int flag = bizPaymentRecordMapper.updateById(payRecord);
            if (flag > 0) {
                log.info("更新支付记录状态成功:{}", payRecord.toString());
            } else {
                log.info("更新支付记录状态失败:{}", payRecord.toString());
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "更新支付记录状态失败");
            }
            Long orderId = payRecord.getOrderId();
            // 更新订单状态
            BizOrder bizOrder = bizOrderMapper.selectById(orderId);
            bizOrder.setStatus(1);
            bizOrder.setPaymentTime(LocalDateTime.now());
            bizOrder.setTransactionId(payStatusDto.getTradeNo());
            int res = bizOrderMapper.updateById(bizOrder);
            if (res > 0) {
                log.info("更新订单状态成功:{}", bizOrder.toString());
            } else {
                log.info("更新订单状态失败:{}", bizOrder.toString());
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "更新订单状态失败");
            }
        }

    }

    @Override
    public void payNotify(HttpServletRequest request, HttpServletResponse response) throws AlipayApiException {
        // 支付宝回调参数
        Map<String, String> params = getStringStringMap(request);

        //验签
        boolean verifyResult = AlipaySignature.rsaCheckV1(params, alipayConfig.getAlipayPublicKey(), alipayConfig.getCharset(), alipayConfig.getSignType());
        //验证成功
        if (verifyResult) {

            //商户订单号
            String outTradeNo = new String(request.getParameter("out_trade_no").getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
            //支付宝交易号
            String tradeNo = new String(request.getParameter("trade_no").getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
            //交易状态
            String tradeStatus = new String(request.getParameter("trade_status").getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
            //appid
            String appId = new String(request.getParameter("app_id").getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
            //total_amount
            String totalAmount = new String(request.getParameter("total_amount").getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);

            //交易成功处理
            if ("TRADE_SUCCESS".equals(tradeStatus)) {
                // TODO 发送消息,没必要强行使用rabbitmq（没有发送短信，库存扣减等等得业务）
//                rabbitTemplate.convertAndSend(RabbitMqConstants.PAY_NOTIFY_EXCHANGE_FANOUT, RabbitMqConstants.PAY_NOTIFY_ROUTING_KEY, bizOrder);

                PayStatusDto payStatusDto = new PayStatusDto();
                payStatusDto.setOutTradeNo(outTradeNo);
                payStatusDto.setTradeStatus(tradeStatus);
                payStatusDto.setAppId(appId);
                payStatusDto.setTradeNo(tradeNo);
                payStatusDto.setTotalAmount(totalAmount);

                currentProxy.saveAliPayStatus(payStatusDto);
                LambdaQueryWrapper<BizOrder> orderQueryWrapper = new LambdaQueryWrapper<>();
                orderQueryWrapper.eq(BizOrder::getTransactionId, tradeNo);
                BizOrder bizOrder = bizOrderMapper.selectOne(orderQueryWrapper);
                // 修改用户的订阅状态
                SysTeamSubscription sysTeamSubscription = new SysTeamSubscription();
                sysTeamSubscription.setOrderId(bizOrder.getId());
                sysTeamSubscription.setTeamId(bizOrder.getTeamId());
                sysTeamSubscription.setUserId(bizOrder.getUserId());
                sysTeamSubscription.setStartTime(new Date());
                sysTeamSubscription.setStatus(1);
                sysTeamSubscriptionMapper.insert(sysTeamSubscription);

                SysTeamUser sysTeamUser = new SysTeamUser();
                sysTeamUser.setUserId(bizOrder.getUserId());
                sysTeamUser.setTeamId(bizOrder.getTeamId());
                sysTeamUser.setRole(0);
                sysTeamUser.setJoinType(0);
                sysTeamUser.setJoinTime(new Date());
                sysTeamUser.setStatus(1);
                sysTeamUserMapper.insert(sysTeamUser);
            }
        }


    }

    @Override
    public BaseResponse<List<BizOrder>> findAllOrders(Integer userId) {
        List<BizOrder> bizOrders = bizOrderMapper.selectList(new LambdaQueryWrapper<BizOrder>().eq(BizOrder::getUserId, userId));
        return ResultUtils.success(bizOrders);
    }

    /**
     * 支付宝回调参数
     *
     * @param request 支付宝回调参数
     * @return 支付宝回调参数
     */
    @NotNull
    private static Map<String, String> getStringStringMap(HttpServletRequest request) {
        Map<String, String> params = new HashMap<String, String>();
        Map requestParams = request.getParameterMap();
        for (Object o : requestParams.keySet()) {
            String name = (String) o;
            String[] values = (String[]) requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
            }
            params.put(name, valueStr);
        }
        return params;
    }

    //从支付宝查询支付结果
    private PayStatusDto queryPayResultFromAlipay(String payNo) {
        //========请求支付宝查询支付结果=============
        AlipayClient alipayClient = new DefaultAlipayClient(alipayConfig.getUrl(), alipayConfig.getAppId(), alipayConfig.getRsaPrivateKey(), alipayConfig.getFormat(), alipayConfig.getCharset(), alipayConfig.getAlipayPublicKey(), alipayConfig.getSignType());
        AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
        JSONObject bizContent = new JSONObject();
        bizContent.put("out_trade_no", payNo);
        request.setBizContent(bizContent.toString());
        AlipayTradeQueryResponse response = null;
        try {
            response = alipayClient.execute(request);
            if (!response.isSuccess()) {
                throw new BusinessException(ErrorCode.SYSTEM_ERROR, "请求支付查询查询失败");
            }
        } catch (AlipayApiException e) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "请求支付查询查询失败");
        }

        //获取支付结果
        String resultJson = response.getBody();
        //转map
        Map resultMap = JSON.parseObject(resultJson, Map.class);
        Map alipay_trade_query_response = (Map) resultMap.get("alipay_trade_query_response");
        //支付结果
        String tradeStatus = (String) alipay_trade_query_response.get("trade_status");
        // 支付金额
        String totalAmount = (String) alipay_trade_query_response.get("total_amount");
        // 支付宝交易号
        String tradeNo = (String) alipay_trade_query_response.get("trade_no");
        //保存支付结果
        PayStatusDto payStatusDto = new PayStatusDto();
        payStatusDto.setOutTradeNo(payNo);
        payStatusDto.setTradeStatus(tradeStatus);
        payStatusDto.setAppId(alipayConfig.getAppId());
        payStatusDto.setTradeNo(tradeNo);
        payStatusDto.setTotalAmount(totalAmount);
        return payStatusDto;

    }

    private BizPaymentRecord getPayRecord(String payNo) {
        LambdaQueryWrapper<BizPaymentRecord> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(BizPaymentRecord::getPayNo, payNo);
        return bizPaymentRecordMapper.selectOne(queryWrapper);
    }
}




